﻿using System;
using System.IO;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;

namespace BITS.PreCompiler.CSharp.Syntax.Extensions
{
    public static partial class CompilationExtension
    {
        public static Boolean Emit(this Compilation @this, String path,
            String name, Boolean withPDB = true, Boolean @throw = true)
        {
            var sb = new StringBuilder();
            var extension = ".dll";

            if (@this.Options.OutputKind == OutputKind.ConsoleApplication)
                extension = ".exe";

            var outputFileName = Path.Combine(path, name + extension);
            var pdbFileName    = Path.Combine(path, name + ".pdb");

            try
            {
                var ilStream = new FileStream(
                    outputFileName, FileMode.OpenOrCreate);

                EmitResult emitResult;

                if (withPDB)
                {
                    var pdbStream = new FileStream(
                        pdbFileName, FileMode.OpenOrCreate);

                    emitResult = @this.Emit(
                        executableStream: ilStream,
                        pdbFileName:      name + ".pdb",
                        pdbStream:        pdbStream);

                    pdbStream.Close();
                }
                else
                {
                    emitResult = @this.Emit(
                        executableStream: ilStream);
                }

                ilStream.Close();

                if (emitResult.Success)
                    return true;

                if (!@throw)
                    return false;

                foreach (var syntaxTree in @this.SyntaxTrees)
                    sb.AppendLine(syntaxTree.GetRoot().GetFullText());

                sb.AppendLine();

                foreach (var diagnostic in emitResult.Diagnostics)
                    sb.AppendLine(diagnostic.ToString());
            }
            catch
            {
                if (!@throw)
                    throw;

                return false;
            }

            throw new ApplicationException(sb.ToString());
        }
    }
}
